// $Id: DataMapper.cs 10 2008-02-29 15:58:02Z mcartoixa $
/*
 *  Copyright (C) 2007 NourY Solutions
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 3 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 */
/*! \file
 * \brief Generic database oriented implementation of Data Mappers.
 *
 * \author $Author: mcartoixa $
 * \date $Date: 2008-02-29 16:58:02 +0100 (ven., 29 févr. 2008) $
 * \version $Revision: 10 $
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Design.Serialization;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Reflection;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Salamanca.Collections;
using Salamanca.DataAccess.Collections;
using Salamanca.DataAccess.Data;
using Salamanca.DataRules;

namespace Salamanca.DataAccess.EnterpriseLibrary.Data
{



    ///////////////////////////////////////////////////////////////////////////
    ///
    /// <summary>Provides data for database oriented <include file="../../doc/Global.doc.xml" path="doc/template[@name='DataMapper']/*" />s events.</summary>
    ///
    ///////////////////////////////////////////////////////////////////////////

    public class DataMapperEventArgs<TDomainEntity>:
        EventArgs
        where TDomainEntity:
            IDomainEntity
    {

        /// <summary>Constructor.</summary>
        public DataMapperEventArgs(TDomainEntity domainModel, IList<DbCommand> commands)
        {
            _DomainEntity=domainModel;
            _Commands=new ReadOnlyCollection<DbCommand>(commands);
        }

        /// <summary>The <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> involved.</summary>
        public TDomainEntity DomainEntity
        {
            get
            {
                return _DomainEntity;
            }
        }

        /// <summary>The <see cref="DbCommand" />s involved.</summary>
        public ReadOnlyCollection<DbCommand> Commands
        {
            get
            {
                return _Commands;
            }
        }

        /// <summary>The <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> involved.</summary>
        private TDomainEntity _DomainEntity;
        /// <summary>The <see cref="IDbCommand" />s involved.</summary>
        private ReadOnlyCollection<DbCommand> _Commands;
    }



    ///////////////////////////////////////////////////////////////////////////
    ///
    /// <summary>Ancestor of a database oriented <include file="../../doc/Global.doc.xml" path="doc/template[@name='DataMapper']/*" />.</summary>
    /// <example>
    ///   <para>This sample uses the sample classes defined for <see cref="DomainEntity{TPrimaryKey,TDataTransferObject}"/>.
    /// It maps the sample <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> to a database table defined as :
    ///     <code>
    /// CREATE TABLE Persons (
    ///     Id INT NOT NULL IDENTITY(1, 1),
    ///     Name VARCHAR(50) NOT NULL,
    ///     PRIMARY KEY (Id)
    /// );
    ///     </code>
    ///   </para>
    ///   <code>
    /// public partial class PersonMapper:
    ///     DataMapper&lt;Person, PersonPrimaryKey, PersonDataTransfer&gt;,
    ///     IPersonMapper
    /// {
    ///     public PersonMapper(Database database, ICacheManager cacheManager)
    ///         base(database, DomainEntityCreator.CreateDefault&lt;Person&gt;(), cacheManager)
    ///     {
    ///     }
    ///
    ///     public DomainEntityKeyedCollection&lt;Person&gt; FindAll(DataMapperCollection dataMappers)
    ///     {
    ///         DbCommand[] commands=new DbCommand[1];
    ///
    ///         commands[0]=Database.GetSqlStringCommand("SELECT * FROM Persons");
    ///
    ///         return Load(commands, dataMappers);
    ///     }
    ///
    ///     protected override IList&lt;DbCommand&gt; CreateSelectCommands(PersonPrimaryKey key)
    ///     {
    ///         DbCommand[] commands=new DbCommand[1];
    ///
    ///         commands[0]=Database.GetSqlStringCommand("SELECT * FROM Persons WHERE Id=@Id");
    ///
    ///         Database.AddParameter(
    ///             commands[0],
    ///             "@Id",
    ///             DbType.Int32,
    ///             ParameterDirection.Input,
    ///             string.Empty,
    ///             DataRowVersion.Default,
    ///             key.Value
    ///         );
    ///
    ///         return commands;
    ///     }
    ///
    ///     protected override IList&lt;DbCommand&gt; CreateDeleteCommands(PersonDataTransfer data)
    ///     {
    ///         DbCommand[] commands=new DbCommand[1];
    ///
    ///         commands[0]=Database.GetSqlStringCommand("DELETE FROM Persons WHERE Id=@Id");
    ///
    ///         Database.AddParameter(
    ///             commands[0],
    ///             "@Id",
    ///             DbType.Int32,
    ///             ParameterDirection.Input,
    ///             string.Empty,
    ///             DataRowVersion.Default,
    ///             data.Id
    ///         );
    ///
    ///         return commands;
    ///     }
    ///
    ///     protected override IList&lt;DbCommand&gt; CreateInsertCommands(PersonDataTransfer data)
    ///     {
    ///         DbCommand[] commands=new DbCommand[1];
    ///
    ///         commands[0]=Database.GetSqlStringCommand("INSERT INTO Persons VALUES(@Name)");
    ///
    ///         Database.AddParameter(
    ///             commands[0],
    ///             "@Name",
    ///             DbType.String,
    ///             ParameterDirection.Input,
    ///             string.Empty,
    ///             DataRowVersion.Default,
    ///             data.Name
    ///         );
    ///
    ///         return commands;
    ///     }
    ///
    ///     protected override IList&lt;DbCommand&gt; CreateUpdateCommands(PersonDataTransfer data)
    ///     {
    ///         DbCommand[] commands=new DbCommand[1];
    ///
    ///         commands[0]=Database.GetSqlStringCommand("UPDATE Persons SET Name=@Name WHERE Id=@Id");
    ///
    ///         Database.AddParameter(
    ///             commands[0],
    ///             "@Name",
    ///             DbType.String,
    ///             ParameterDirection.Input,
    ///             string.Empty,
    ///             DataRowVersion.Default,
    ///             data.Name
    ///         );
    ///         Database.AddParameter(
    ///             commands[0],
    ///             "@Id",
    ///             DbType.Int32,
    ///             ParameterDirection.Input,
    ///             string.Empty,
    ///             DataRowVersion.Default,
    ///             data.Id
    ///         );
    ///
    ///         return commands;
    ///     }
    ///
    ///     protected override PersonDataTransfer GetDataTransferObject(IList&lt;IDataRecord&gt; records)
    ///     {
    ///         PersonDataTransfer data=new PersonDataTransfer();
    ///
    ///         int ord=record.GetOrdinal("Id");
    ///         if (!record.IsDBNull(ord))
    ///             data.Id=record.GetInt32(ord);
    ///
    ///         ord=record.GetOrdinal("Name");
    ///         if (!record.IsDBNull(ord))
    ///             data.Name=record.GetString(ord);
    ///
    ///         return data;
    ///     }
    ///
    ///     protected override void OnInserted(Person domainModel, IList&lt;DbCommand&gt; commands)
    ///     {
    ///         DbCommand command=Database.GetSqlStringCommand("SELECT @@IDENTITY");
    ///         command.Transaction=commands[0].Transaction;
    ///
    ///         int id=0;
    ///         if (command.Transaction!=null)
    ///             id=Convert.ToInt32(database.ExecuteScalar(command, command.Transaction));
    ///         else
    ///             id=Convert.ToInt32(database.ExecuteScalar(command));
    ///         domainModel.SetId(id);
    ///
    ///         base.OnInserted(domainModel, commands);
    ///     }
    /// }
    ///   </code>
    /// </example>
    ///
    ///////////////////////////////////////////////////////////////////////////

    public abstract class DataMapper<TDomainEntity, TPrimaryKey, TDataTransferObject>:
        Salamanca.DataAccess.DataMapperBase<TDomainEntity, TPrimaryKey, TDataTransferObject>
        where TDomainEntity:
            DomainEntity<TPrimaryKey, TDataTransferObject>
        where TPrimaryKey:
            IPrimaryKey,
            new()
        where TDataTransferObject:
            class, // SOAP serialization does not accept structs...
            IDataTransferObject,
            new()
    {



        /// <summary>Constructor.</summary>
        /// <param name="database">The database connection used to deal with the data.</param>
        /// <param name="instanceCreator">Member used to create new instances for the type. May be <c>null</c>, in which case the default constructor for the type will be used.</param>
        /// <param name="cacheManager">A cache manager. Must not be <c>null</c>.</param>
        protected DataMapper(Database database, DomainEntityCreator<TDomainEntity> instanceCreator, ICacheManager cacheManager):
            base(instanceCreator, cacheManager)
        {
            _Database=database;
        }



        /// <summary>Finds the <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> instance with the specified key.</summary>
        //        /// <param name="key">The key against which the command is created </param>
        public override TDomainEntity Find(TPrimaryKey key, DataMapperCollection dataMappers)
        {
            TDomainEntity ret=null;

            ret=GetInstance(key, null);
            if (ret==null)
            {
                DomainEntityKeyedCollection<TDomainEntity> found=Load(CreateSelectCommands(key), dataMappers);
                if (found.Contains(key))
                    ret=found[key];
            }

            return ret;
        }



        /// <summary>Refreshes the data of the specified <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> instance from the database.</summary>
        /// <param name="domainModel">The <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> instance to be refreshed.</param>
        protected override void Refresh(TDomainEntity domainModel)
        {
            Debug.Assert(domainModel!=null);
            if (domainModel==null)
                throw new ArgumentNullException("domainModel");

            using (DisposableCollection<DbCommand> commands=new DisposableCollection<DbCommand>(CreateSelectCommands((TPrimaryKey)((IDomainEntity)domainModel).Id)))
            {
                OnRefreshing(domainModel, commands);

                foreach (DbCommand command in commands)
                    Traces.TraceBeforeCommand(Configuration.DataSwitch, command, "ExecuteReader");

                using (DataReaderCollection<IDataReader> readers=new DataReaderCollection<IDataReader>())
                {
                    foreach (DbCommand command in commands)
                    {
                        readers.Add(Database.ExecuteReader(command));

                        Traces.TraceAfterCommand(Configuration.DataSwitch, command, "ExecuteReader");
                    }

                    // Get the first result.
                    // If no data was found, an exception is raised.
                    readers.Read();
                    if (Configuration.DataSwitch.TraceVerbose)
                        foreach (IDataReader reader in readers)
                        {
                            object[] tmp=new object[reader.FieldCount];
                            reader.GetValues(tmp);
                            Trace.WriteLine(Traces.GetValueTrace(tmp));
                        }

                    // Fill the instance with data
                    TransferData(domainModel, GetDataTransferObject(readers.DataRecords));
                }

                OnRefreshed(domainModel, commands);
            }
        }



        /// <summary>Creates a database command that returns the data for the instance with the specified key.</summary>
        /// <param name="key">The key against which the command is created </param>
        /// <returns>The database commands.</returns>
        protected abstract IList<DbCommand> CreateSelectCommands(TPrimaryKey key);

        /// <summary>Creates a database command that deletes the data of the instance.</summary>
        /// <param name="data">The data to be deleted.</param>
        /// <returns>The database commands.</returns>
        protected abstract IList<DbCommand> CreateDeleteCommands(TDataTransferObject data);

        /// <summary>Creates a database command that inserts the data of the instance.</summary>
        /// <param name="data">The data to be inserted.</param>
        /// <returns>The database commands.</returns>
        protected abstract IList<DbCommand> CreateInsertCommands(TDataTransferObject data);

        /// <summary>Creates a database command that updates the data of the instance.</summary>
        /// <param name="data">The data to be updated.</param>
        /// <returns>The database commands.</returns>
        protected abstract IList<DbCommand> CreateUpdateCommands(TDataTransferObject data);

        /// <summary>Gets the <include file="../../doc/Global.doc.xml" path="doc/template[@name='DataTransferObject']/*" />
        /// filled with the specified data.</summary>
        /// <param name="records">The records containing the data.</param>
        /// <returns>The <include file="../../doc/Global.doc.xml" path="doc/template[@name='DataTransferObject']/*" /> containing the data.</returns>
        protected abstract TDataTransferObject GetDataTransferObject(IList<IDataRecord> records);



        /// <summary>Returns the list of <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> instances
        /// returned by the specified database <paramref name="cmds">commands</paramref>.</summary>
        protected DomainEntityKeyedCollection<TDomainEntity> Load(IList<DbCommand> cmds, DataMapperCollection dataMappers)
        {
            List<TDomainEntity> ret=new List<TDomainEntity>();

            using (DisposableCollection<DbCommand> commands=new DisposableCollection<DbCommand>(cmds))
            {
                foreach (DbCommand command in commands)
                    Traces.TraceBeforeCommand(Configuration.DataSwitch, command, "ExecuteReader");

                using (DataReaderCollection<IDataReader> readers=new DataReaderCollection<IDataReader>())
                {
                    foreach (DbCommand command in commands)
                    {
                        readers.Add(Database.ExecuteReader(command));

                        Traces.TraceAfterCommand(Configuration.DataSwitch, command, "ExecuteReader");
                    }

                    while (readers.Read())
                    {
                        if (Configuration.DataSwitch.TraceVerbose)
                            foreach (IDataReader reader in readers)
                            {
                                object[] tmp=new object[reader.FieldCount];
                                reader.GetValues(tmp);
                                Trace.WriteLine(Traces.GetValueTrace(tmp));
                            }

                        // Creation of the Domain Entity instance
                        TDataTransferObject data=GetDataTransferObject(readers.DataRecords);
                        TDomainEntity obj=CreateDomainEntity(data);
                        ((IDomainEntity)obj).DataMappers=dataMappers;

                        // Fill the instance with data
                        TransferData(obj, data);

                        // Update the result set
                        TPrimaryKey key=(TPrimaryKey)((IDomainEntity)obj).Id;
                        ret.Add(GetInstance(key, obj));
                    }
                }
            }

            return new DomainEntityKeyedCollection<TDomainEntity>(ret);
        }



        /// <summary>Deletes the data of the specified <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> instance.</summary>
        //        /// <param name="domainModel">The <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> instance to be deleted.</param>
        protected override void Delete(TDomainEntity domainModel, IPersistenceContext context)
        {
            Debug.Assert(context!=null);
            if (context==null)
                throw new ArgumentNullException("context");
            Debug.Assert(domainModel!=null);
            if (domainModel==null)
                throw new ArgumentNullException("domainModel");
            Debug.Assert(!((IDomainEntity)domainModel).IsNew);
            if (((IDomainEntity)domainModel).IsNew)
                throw new InvalidOperationException(Resources.SR.CannotDeleteNewDomainEntity);

            domainModel.TriggerDeletingEvent(new PersistenceEventArgs(context));

            if (context.ForceAction || !((IDomainEntity)domainModel).IsNew)
            {
                using (DisposableCollection<DbCommand> commands=new DisposableCollection<DbCommand>(CreateDeleteCommands((TDataTransferObject)((ITransferable)domainModel).GetData())))
                {
                    Transaction t=context.Transaction as Transaction;
                    if (t!=null)
                        foreach (DbCommand command in commands)
                            if (command.Transaction==null)
                                command.Transaction=(DbTransaction)t;

                    TPrimaryKey key=(TPrimaryKey)((IDomainEntity)domainModel).Id;

                    DoDeleting(domainModel, commands, context);

                    foreach (DbCommand command in commands)
                    {
                        Traces.TraceBeforeCommand(Configuration.DataSwitch, command, "ExecuteNonQuery");

                        if (command.Transaction!=null)
                            Database.ExecuteNonQuery(command, command.Transaction);
                        else
                            Database.ExecuteNonQuery(command);

                        Traces.TraceAfterCommand(Configuration.DataSwitch, command, "ExecuteNonQuery");
                    }

                    DoDeleted(domainModel, commands, context);

                    CacheManager.Remove(key);
                }
            }

            domainModel.TriggerDeletedEvent(new PersistenceEventArgs(context));
        }



        /// <summary>Saves the data of the specified <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> instance.</summary>
        //        /// <param name="domainModel">The <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> instance to be saved.</param>
        protected override void Save(TDomainEntity domainModel, IPersistenceContext context)
        {
            Debug.Assert(context!=null);
            if (context==null)
                throw new ArgumentNullException("context");
            Debug.Assert(domainModel!=null);
            if (domainModel==null)
                throw new ArgumentNullException("domainModel");

            domainModel.TriggerSavingEvent(new PersistenceEventArgs(context));

            if (context.ForceAction || (domainModel.IsModified && (((IDomainEntity)domainModel).IsNew || ((IDomainEntity)domainModel).IsLoaded)))
            {
                if (!domainModel.Validate())
                    throw new BrokenRulesException(((IValidatable)domainModel).GetBrokenRules(), domainModel);

                // Create the commands
                List<DbCommand> cmds=new List<DbCommand>();

                if (((IDomainEntity)domainModel).IsNew)
                    DoInserting(domainModel, cmds, context);
                else
                    DoUpdating(domainModel, cmds, context);

                if (((IDomainEntity)domainModel).IsNew)
                    cmds.AddRange(CreateInsertCommands((TDataTransferObject)((ITransferable)domainModel).GetData()));
                else
                    cmds.AddRange(CreateUpdateCommands((TDataTransferObject)((ITransferable)domainModel).GetData()));

                using (DisposableCollection<DbCommand> commands=new DisposableCollection<DbCommand>(cmds))
                {
                    Transaction t=context.Transaction as Transaction;
                    if (t!=null)
                        foreach (DbCommand command in commands)
                            if (command.Transaction==null)
                                command.Transaction=(DbTransaction)t;

                    // Execution
                    foreach (DbCommand command in commands)
                    {
                        Traces.TraceBeforeCommand(Configuration.DataSwitch, command, "ExecuteNonQuery");

                        if (command.Transaction!=null)
                            Database.ExecuteNonQuery(command, command.Transaction);
                        else
                            Database.ExecuteNonQuery(command);

                        Traces.TraceAfterCommand(Configuration.DataSwitch, command, "ExecuteNonQuery");
                    }

                    if (((IDomainEntity)domainModel).IsNew)
                    {
                        DoInserted(domainModel, commands, context);
                        CacheManager.Add((TPrimaryKey)((IDomainEntity)domainModel).Id, domainModel);
                    } else
                        DoUpdated(domainModel, commands, context);
                }

            }

            domainModel.TriggerSavedEvent(new PersistenceEventArgs(context));
        }

        private void DoDeleted(TDomainEntity domainModel, IList<DbCommand> commands, IPersistenceContext context)
        {
            domainModel.SetNew(true);
            domainModel.SetLoaded(false);

            OnDeleted(domainModel, commands);
        }

        private void DoInserted(TDomainEntity domainModel, IList<DbCommand> commands, IPersistenceContext context)
        {
            domainModel.SetModified(false);
            domainModel.SetNew(false);
            domainModel.SetLoaded(true);

            OnInserted(domainModel, commands);
        }

        private void DoUpdated(TDomainEntity domainModel, IList<DbCommand> commands, IPersistenceContext context)
        {
            domainModel.SetModified(false);

            OnUpdated(domainModel, commands);
        }

        private void DoDeleting(TDomainEntity domainModel, IList<DbCommand> commands, IPersistenceContext context)
        {
            OnDeleting(domainModel, commands);
        }

        private void DoInserting(TDomainEntity domainModel, IList<DbCommand> commands, IPersistenceContext context)
        {
            OnInserting(domainModel, commands);
        }

        private void DoUpdating(TDomainEntity domainModel, IList<DbCommand> commands, IPersistenceContext context)
        {
            OnUpdating(domainModel, commands);
        }

        /// <summary>Raises the <see cref="Refreshed" /> event.</summary>
        /// <remarks>
        ///   <include file="../../doc/Global.doc.xml" path="doc/template[@name='OnEvent']/*" />
        /// </remarks>
        protected virtual void OnRefreshed(TDomainEntity domainModel, IList<DbCommand> commands)
        {
            if (Refreshed!=null)
                Refreshed(this, new DataMapperEventArgs<TDomainEntity>(domainModel, commands));

            domainModel.TriggerRefreshedEvent(new EventArgs());
        }

        /// <summary>Raises the <see cref="Refreshing" /> event.</summary>
        /// <remarks>
        ///   <include file="../../doc/Global.doc.xml" path="doc/template[@name='OnEvent']/*" />
        /// </remarks>
        protected virtual void OnRefreshing(TDomainEntity domainModel, IList<DbCommand> commands)
        {
            if (Refreshing!=null)
                Refreshing(this, new DataMapperEventArgs<TDomainEntity>(domainModel, commands));

            domainModel.TriggerRefreshingEvent(new EventArgs());
        }



        /// <summary>Raises the <see cref="Deleted" /> event.</summary>
        /// <remarks>
        ///   <include file="../../doc/Global.doc.xml" path="doc/template[@name='OnEvent']/*" />
        /// </remarks>
        protected virtual void OnDeleted(TDomainEntity domainModel, IList<DbCommand> commands)
        {
            if (Deleted!=null)
                Deleted(this, new DataMapperEventArgs<TDomainEntity>(domainModel, commands));
        }



        /// <summary>Raises the <see cref="Inserted" /> event.</summary>
        /// <remarks>
        ///   <include file="../../doc/Global.doc.xml" path="doc/template[@name='OnEvent']/*" />
        /// </remarks>
        protected virtual void OnInserted(TDomainEntity domainModel, IList<DbCommand> commands)
        {
            if (Inserted!=null)
                Inserted(this, new DataMapperEventArgs<TDomainEntity>(domainModel, commands));
        }



        /// <summary>Raises the <see cref="Updated" /> event.</summary>
        /// <remarks>
        ///   <include file="../../doc/Global.doc.xml" path="doc/template[@name='OnEvent']/*" />
        /// </remarks>
        protected virtual void OnUpdated(TDomainEntity domainModel, IList<DbCommand> commands)
        {
            if (Updated!=null)
                Updated(this, new DataMapperEventArgs<TDomainEntity>(domainModel, commands));
        }



        /// <summary>Raises the <see cref="Deleting" /> event.</summary>
        /// <remarks>
        ///   <include file="../../doc/Global.doc.xml" path="doc/template[@name='OnEvent']/*" />
        /// </remarks>
        protected virtual void OnDeleting(TDomainEntity domainModel, IList<DbCommand> commands)
        {
            if (Deleting!=null)
                Deleting(this, new DataMapperEventArgs<TDomainEntity>(domainModel, commands));
        }



        /// <summary>Raises the <see cref="Inserting" /> event.</summary>
        /// <remarks>
        ///   <include file="../../doc/Global.doc.xml" path="doc/template[@name='OnEvent']/*" />
        /// </remarks>
        protected virtual void OnInserting(TDomainEntity domainModel, IList<DbCommand> commands)
        {
            if (Inserting!=null)
                Inserting(this, new DataMapperEventArgs<TDomainEntity>(domainModel, commands));
        }



        /// <summary>Raises the <see cref="Updating" /> event.</summary>
        /// <remarks>
        ///   <include file="../../doc/Global.doc.xml" path="doc/template[@name='OnEvent']/*" />
        /// </remarks>
        protected virtual void OnUpdating(TDomainEntity domainModel, IList<DbCommand> commands)
        {
            if (Updating!=null)
                Updating(this, new DataMapperEventArgs<TDomainEntity>(domainModel, commands));
        }



        /// <summary>Gets the database connection.</summary>
        /// <value>The database connection.</value>
        protected Database Database
        {
            get
            {
                return _Database;
            }
        }



        /// <summary>The database connection.</summary>
        private Database _Database;

        /// <summary>Occurs when a <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> has been <see cref="DomainEntity{TPrimaryKey,TDataTransferObject}.Refresh">refreshed</see>.</summary>
        public event EventHandler<DataMapperEventArgs<TDomainEntity>> Refreshed;
        /// <summary>Occurs when a <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> is about to be <see cref="DomainEntity{TPrimaryKey,TDataTransferObject}.Refresh">refreshed</see>.</summary>
        public event EventHandler<DataMapperEventArgs<TDomainEntity>> Refreshing;
        /// <summary>Occurs when a <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> has been <see cref="DomainEntity{TPrimaryKey,TDataTransferObject}.Delete()">deleted</see>.</summary>
        public event EventHandler<DataMapperEventArgs<TDomainEntity>> Deleted;
        /// <summary>Occurs when a <see cref="IDomainEntity.IsNew">new</see> <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> has been <see cref="DomainEntity{TPrimaryKey,TDataTransferObject}.Save()">saved</see>.</summary>
        public event EventHandler<DataMapperEventArgs<TDomainEntity>> Inserted;
        /// <summary>Occurs when a <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> has been <see cref="DomainEntity{TPrimaryKey,TDataTransferObject}.Save()">saved</see>.</summary>
        public event EventHandler<DataMapperEventArgs<TDomainEntity>> Updated;
        /// <summary>Occurs when a <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> is about to be <see cref="DomainEntity{TPrimaryKey,TDataTransferObject}.Delete()">deleted</see>.</summary>
        public event EventHandler<DataMapperEventArgs<TDomainEntity>> Deleting;
        /// <summary>Occurs when a <see cref="IDomainEntity.IsNew">new</see> <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> is about to be <see cref="DomainEntity{TPrimaryKey,TDataTransferObject}.Save()">saved</see>.</summary>
        public event EventHandler<DataMapperEventArgs<TDomainEntity>> Inserting;
        /// <summary>Occurs when a <include file="../../doc/Global.doc.xml" path="doc/template[@name='DomainEntity']/*" /> is about to be <see cref="DomainEntity{TPrimaryKey,TDataTransferObject}.Save()">saved</see>.</summary>
        public event EventHandler<DataMapperEventArgs<TDomainEntity>> Updating;

    }
}
